package net.ermannofranco.xmltest;

import static net.ermannofranco.xml.schema.Process.SKIP;
import static net.ermannofranco.xml.schema.Use.OPTIONAL;
import static net.ermannofranco.xml.schema.Use.REQUIRED;
import static net.ermannofranco.xml.schema.XmlType.BOOLEAN;
import static net.ermannofranco.xml.schema.XmlType.INTEGER;
import static net.ermannofranco.xml.schema.XmlType.NON_NEG_INTEGER;
import static net.ermannofranco.xml.schema.XmlType.POS_INTEGER;
import static net.ermannofranco.xml.schema.XmlType.STRING;
import net.ermannofranco.xml.schema.ComplexType;
import net.ermannofranco.xml.schema.Element;
import net.ermannofranco.xml.schema.Schema;
import net.ermannofranco.xml.schema.Sequence;
import net.ermannofranco.xml.schema.SimpleType;

import org.junit.Assert;
import org.junit.Test;

public class EhcacheSchema extends Schema {

	private static final long serialVersionUID = 4685793901048380386L;

	public EhcacheSchema() {

		super("xs", 1.7);
		setElemFormDefQualified(true);

		SimpleType notificationScope = addSimpleType("notificationScope");
		notificationScope.setRestriction(STRING).addEnumerationFacet("local",
				"remote", "all");

		SimpleType writeModeType = addSimpleType("writeModeType");
		writeModeType.setRestriction(STRING).addEnumerationFacet(
				"write-through", "write-behind");

		SimpleType transactionalMode = addSimpleType("transactionalMode");
		transactionalMode.setRestriction(STRING).addEnumerationFacet("off",
				"xa");

		SimpleType monitoringType = addSimpleType("monitoringType");
		monitoringType.setRestriction(STRING).addEnumerationFacet("autodetect",
				"on", "off");

		SimpleType terracottaCacheValueType = addSimpleType("terracottaCacheValueType");
		terracottaCacheValueType.setRestriction(STRING).addEnumerationFacet(
				"serialization", "identity");

		Element diskStore = addElem("diskStore");
		diskStore.setComplexType().addTagAttribute("path", OPTIONAL);

		Element transactionManagerLookup = addElem("transactionManagerLookup");
		ComplexType ct = transactionManagerLookup.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheManagerEventListenerFactory = addElem("cacheManagerEventListenerFactory");
		ct = cacheManagerEventListenerFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheManagerPeerProviderFactory = addElem("cacheManagerPeerProviderFactory");
		ct = cacheManagerPeerProviderFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheManagerPeerListenerFactory = addElem("cacheManagerPeerListenerFactory");
		ct = cacheManagerPeerListenerFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheWriterFactory = addElem("cacheWriterFactory");
		ct = cacheWriterFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheEventListenerFactory = addElem("cacheEventListenerFactory");
		ct = cacheEventListenerFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);
		ct.addTagAttribute("listenFor", notificationScope, OPTIONAL)
				.setDefault("all");

		Element bootstrapCacheLoaderFactory = addElem("bootstrapCacheLoaderFactory");
		ct = bootstrapCacheLoaderFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheExtensionFactory = addElem("cacheExtensionFactory");
		ct = cacheExtensionFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheExceptionHandlerFactory = addElem("cacheExceptionHandlerFactory");
		ct = cacheExceptionHandlerFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element cacheLoaderFactory = addElem("cacheLoaderFactory");
		ct = cacheLoaderFactory.setComplexType();
		ct.addTagAttribute("class", REQUIRED);
		ct.addTagAttribute("properties", OPTIONAL);
		ct.addTagAttribute("propertySeparator", OPTIONAL);

		Element terracotta = addElem("terracotta");
		ct = terracotta.setComplexType();
		ct.addTagAttribute("clustered", BOOLEAN, OPTIONAL).setDefaultTrue();
		ct.addTagAttribute("valueMode", terracottaCacheValueType, OPTIONAL)
				.setDefault("serialization");
		ct.addTagAttribute("coherentReads", BOOLEAN, OPTIONAL).setDefaultTrue();
		ct.addTagAttribute("localKeyCache", BOOLEAN, OPTIONAL)
				.setDefaultFalse();
		ct.addTagAttribute("localKeyCacheSize", POS_INTEGER, OPTIONAL)
				.setDefault("300000");
		ct.addTagAttribute("orphanEviction", BOOLEAN, OPTIONAL)
				.setDefaultTrue();
		ct.addTagAttribute("orphanEvictionPeriod", POS_INTEGER, OPTIONAL)
				.setDefault("4");
		ct.addTagAttribute("copyOnRead", BOOLEAN, OPTIONAL).setDefaultFalse();
		ct.addTagAttribute("coherent", BOOLEAN, OPTIONAL).setDefaultTrue();
		ct.addTagAttribute("synchronousWrites", BOOLEAN, OPTIONAL)
				.setDefaultFalse();

		Element cacheWriter = addElem("cacheWriter");
		ct = cacheWriter.setComplexType();
		ct.setSequence().addElem(cacheWriterFactory).setZeroOrOneOccurs();
		ct.addTagAttribute("writeMode", writeModeType, OPTIONAL).setDefault(
				"write-through");
		ct.addTagAttribute("notifyListenersOnException", BOOLEAN, OPTIONAL)
				.setDefaultFalse();
		ct.addTagAttribute("minWriteDelay", NON_NEG_INTEGER, OPTIONAL)
				.setDefaultOne();
		ct.addTagAttribute("maxWriteDelay", NON_NEG_INTEGER, OPTIONAL)
				.setDefaultOne();
		ct.addTagAttribute("rateLimitPerSecond", NON_NEG_INTEGER, OPTIONAL)
				.setDefaultZero();
		ct.addTagAttribute("writeCoalescing", BOOLEAN, OPTIONAL)
				.setDefaultFalse();
		ct.addTagAttribute("writeBatching", BOOLEAN, OPTIONAL)
				.setDefaultFalse();
		ct.addTagAttribute("writeBatchSize", POS_INTEGER, OPTIONAL)
				.setDefaultOne();
		ct.addTagAttribute("retryAttempts", NON_NEG_INTEGER, OPTIONAL)
				.setDefaultZero();
		ct.addTagAttribute("retryAttemptDelaySeconds", NON_NEG_INTEGER,
				OPTIONAL).setDefaultOne();

		Element terracottaConfig = addElem("terracottaConfig");
		ct = terracottaConfig.setComplexType();
		ct.addTagAttribute("url", OPTIONAL).setDefault("localhost:9510");
		ct.addTagAttribute("registerStatsMBean", BOOLEAN, OPTIONAL);
		ct.setSequence().addElem("tc-config").setZeroOrOneOccurs()
				.setComplexType().setSequence().addAny().setAllPossibleOccurs()
				.processContents(SKIP);

		addCommentedText("add clone support for addition of cacheExceptionHandler. Important!");
		Element defaultCache = addElem("defaultCache");
		ct = defaultCache.setComplexType();
		Sequence seq = ct.setSequence();
		seq.addElem(cacheEventListenerFactory).setAllPossibleOccurs();
		seq.addElem(cacheExtensionFactory).setAllPossibleOccurs();
		seq.addElem(cacheLoaderFactory).setAllPossibleOccurs();
		seq.addElem(bootstrapCacheLoaderFactory).setZeroOrOneOccurs();
		seq.addElem(cacheExceptionHandlerFactory).setZeroOrOneOccurs();
		seq.addElem(terracotta).setZeroOrOneOccurs();
		seq.addElem(cacheWriter).setZeroOrOneOccurs();

		ct
				.addTagAttribute("diskExpiryThreadIntervalSeconds", INTEGER,
						OPTIONAL);
		ct.addTagAttribute("diskSpoolBufferSizeMB", INTEGER, OPTIONAL);
		ct.addTagAttribute("diskPersistent", BOOLEAN, OPTIONAL);
		ct.addTagAttribute("diskAccessStripes", INTEGER, OPTIONAL)
				.setDefaultOne();
		ct.addTagAttribute("eternal", BOOLEAN, REQUIRED);
		ct.addTagAttribute("maxElementsInMemory", INTEGER, REQUIRED);
		ct.addTagAttribute("clearOnFlush", BOOLEAN, OPTIONAL);
		ct.addTagAttribute("memoryStoreEvictionPolicy", STRING, OPTIONAL);
		ct.addTagAttribute("overflowToDisk", BOOLEAN, REQUIRED);
		ct.addTagAttribute("timeToIdleSeconds", INTEGER, OPTIONAL);
		ct.addTagAttribute("timeToLiveSeconds", INTEGER, OPTIONAL);
		ct.addTagAttribute("maxElementsOnDisk", INTEGER, OPTIONAL);
		ct.addTagAttribute("transactionalMode", transactionalMode, OPTIONAL)
				.setDefault("off");
		ct.addTagAttribute("statistics", BOOLEAN, OPTIONAL).setDefaultTrue();

		Element cache = addElem("cache");
		ct = cache.setComplexType();
		seq = ct.setSequence();
		seq.addElem(cacheEventListenerFactory).setAllPossibleOccurs();
		seq.addElem(cacheExtensionFactory).setAllPossibleOccurs();
		seq.addElem(cacheLoaderFactory).setAllPossibleOccurs();
		seq.addElem(bootstrapCacheLoaderFactory).setZeroOrOneOccurs();
		seq.addElem(cacheExceptionHandlerFactory).setZeroOrOneOccurs();
		seq.addElem(terracotta).setZeroOrOneOccurs();
		seq.addElem(cacheWriter).setZeroOrOneOccurs();
		ct
				.addTagAttribute("diskExpiryThreadIntervalSeconds", INTEGER,
						OPTIONAL);
		ct.addTagAttribute("diskSpoolBufferSizeMB", INTEGER, OPTIONAL);
		ct.addTagAttribute("diskPersistent", BOOLEAN, OPTIONAL);
		ct.addTagAttribute("diskAccessStripes", INTEGER, OPTIONAL)
				.setDefaultOne();
		ct.addTagAttribute("eternal", BOOLEAN, REQUIRED);
		ct.addTagAttribute("maxElementsInMemory", INTEGER, REQUIRED);
		ct.addTagAttribute("clearOnFlush", BOOLEAN, OPTIONAL);
		ct.addTagAttribute("name", STRING, REQUIRED);
		ct.addTagAttribute("memoryStoreEvictionPolicy", STRING, OPTIONAL);
		ct.addTagAttribute("overflowToDisk", BOOLEAN, REQUIRED);
		ct.addTagAttribute("timeToIdleSeconds", INTEGER, OPTIONAL);
		ct.addTagAttribute("timeToLiveSeconds", INTEGER, OPTIONAL);
		ct.addTagAttribute("maxElementsOnDisk", INTEGER, OPTIONAL);
		ct.addTagAttribute("transactionalMode", transactionalMode, OPTIONAL)
				.setDefault("off");
		ct.addTagAttribute("statistics", BOOLEAN, OPTIONAL).setDefaultTrue();

		ct = addElem("ehcache").setComplexType();
		seq = ct.setSequence();
		seq.addElem(diskStore).setZeroOrOneOccurs();
		seq.addElem(transactionManagerLookup).setZeroOrOneOccurs();
		seq.addElem(cacheManagerEventListenerFactory).setZeroOrOneOccurs();
		seq.addElem(cacheManagerPeerProviderFactory).setAllPossibleOccurs();
		seq.addElem(cacheManagerPeerListenerFactory).setAllPossibleOccurs();
		seq.addElem(terracottaConfig).setZeroOrOneOccurs();
		seq.addElem(defaultCache);
		seq.addElem(cache).setAllPossibleOccurs();
		ct.addTagAttribute("name", OPTIONAL);
		ct.addTagAttribute("updateCheck", BOOLEAN, OPTIONAL).setDefaultTrue();
		ct.addTagAttribute("monitoring", monitoringType, OPTIONAL);
		ct.addTagAttribute("dynamicConfig", BOOLEAN, OPTIONAL);
	}

	@Test
	public void test() {
		print();
		Assert.assertEquals(0, getErrors());
	}
}
